import java.io.*;



public class Mythread implements Runnable {
	private Boolarray booray;
	static private int booray_true;
	private int tid; //thread id
	private int tcnt; //thread count
	static public boolean debug=false;
	static volatile public long slowdown=0; //das abbremsen der einzellnen threads aus der aufgabenstellung
	static boolean sync=true; //synchronisations version einschalten
	public int anzbereich=0; //grad zu faul ne getter zuschreiben
	
	//1nen thread mit neuem Boolarray erzeugen
	public Mythread(){
		booray = new Boolarray();
	}
	//1nen Thread mit Kopierten Boolarray erstellen
	public Mythread(Boolarray booray){
		this.booray = new Boolarray(booray); 
	}
	//mehrere threads erstellen
	//n=anzahl gestarteter threads; id = id des neuen threads
	public Mythread(int n, int id, Boolarray booray){
		this.booray=booray; //!Softcopy
		this.tcnt=n;
		this.tid=id;
	}
	
	//getter
	static public int getBoorayTrue(){
		return booray_true;
	}
	public int getTid(){
		return this.tid;
	}
	public int getThreadCount(){
		return this.tcnt;
	}
	static public void setWahr(int n){
		booray_true=n;
	} 
	synchronized static void addBoorayTrue(int n){
		booray_true += n;
	}
	public void run() { 
		
		int divisor = (this.tcnt == 0)?1:this.tcnt;
		int x = this.tid * (this.booray.getRayLen() / divisor);
		int y = x + (this.booray.getRayLen() / divisor);
		
		if( this.tid == this.tcnt-1 )
			y=this.booray.getRayLen();
		y=( y>=this.booray.getRayLen() )?this.booray.getRayLen():y;
		x=( x>=this.booray.getRayLen() )?this.booray.getRayLen():x;
		
		anzbereich = this.booray.countLim(x,y);
	
		if( true == sync ){ //thread arbeitet synchronisiert und schreibt in static boolray;
			addBoorayTrue(anzbereich);
		}
		if (debug)
			System.out.println( "Thread ID: "+ this.tid
				+ "\n   Anzahl True-werte in booray["
				+ x + "," + y +"]: "
				+ anzbereich);
		
		try {
			Thread.sleep(slowdown);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("Unterbrochen!\n");
		}		
	}
	
	//schreibt den inhalt von datei in datei filename, cat == true -> kein überschreiben, text anfügen
	static public void writeStatistiks(String filename, String data, boolean cat){
		try {
			FileOutputStream ausgabe = new FileOutputStream(filename, cat); 
			String text = data + "\n";
			for(int i=0; i<text.length(); i++)
				ausgabe.write((byte)text.charAt(i));
			ausgabe.close();
		} catch (FileNotFoundException e1) {
			System.out.print("Datei: " + filename + "konnte nicht gefunden werden!\n");
			e1.printStackTrace();
		} catch (IOException e) {
			System.out.println("Schreibfehler bei Datei: " + filename );
			e.printStackTrace();
		}
	}
	//führt gnuplot aus und zeigt die statistiken an
	static public void showStatistiks(String filename){
		try{
			FileOutputStream ausgabe = new FileOutputStream(".doplot.plt", false);
			String text = "plot \"" + filename + "\" with lines\n";
			for(int i=0; i<text.length(); i++)
				ausgabe.write((byte)text.charAt(i));
			ausgabe.close();
		}catch(IOException e){
			e.printStackTrace();
		}
		try{
			Runtime.getRuntime().exec("/usr/bin/gnuplot -persist .doplot.plt");
		}catch(IOException e){
			e.printStackTrace();
			System.out.println("Fehler, konnte gnuplot nicht richtig ausführen.");
		}	
	}
	
	public void showCores(){
		System.out.println("Anzahl der Kerne: " + Runtime.getRuntime().availableProcessors() );
	}
	
	public void threadHandler(int rayLen, int threads, int slowdown, boolean sync){
		Boolarray booray = new Boolarray(rayLen);
		booray.fillRandom();
		//booray.fillFirstN(500);
		//for(int i=3000; i<5000; i++)
		//	booray.setRay(i, true);
		
		//time=zeit zwischen x threads, timeSum=Zeit ausführung; timeDiff=Zeit den 1 thread braucht
		long time=0, timeSum=0, timeDiff=0;	
		Mythread.slowdown=slowdown; //x m.sekunden warten
		int anz_threads=threads;
		int ret=0;
		Mythread.sync=sync;
		
		String filename = "stat_werte.plt";
		
		timeSum=System.currentTimeMillis();
		
		for(int j=0; j<anz_threads; j++){
			Mythread mt[] = new Mythread[anz_threads];
			Thread t[] = new Thread[anz_threads];

			 
			timeDiff=System.currentTimeMillis();
			
			//threads initialisieren
			for(int i=0; i<j; i++){
				mt[i]=new Mythread(j, i, booray);
				 t[i]=new Thread(mt[i]);
				 t[i].start();	
			}
			for(int i=0; i<j; i++){
				try {
					t[i].join(10000); 
				}
				catch ( InterruptedException e ) { //wird nie von join erreicht -.-
					t[i].interrupt(); // thread abbrechen
					System.out.println("Achtung!!! Thread: " + i 
						+ " wurde unterbrochen!!!\n Es können sich falsche werte ergeben haben!!!");
				}
				if( t[i].isAlive() == false )
					if(!Mythread.sync) //falls sync aktiviert variable hochzählen
						ret+=mt[i].anzbereich;
					t[i].interrupt();
			}
			if(!Mythread.sync){
				Mythread.setWahr(ret);
			}
			

			timeDiff=System.currentTimeMillis()-timeDiff;
			
			time=time+timeDiff;
			if(j%10 == 0 || 1 == j || 2 == j || 4 == j){ //werte aller 10 threads kumulieren
				boolean overwrite = (j==0)?false:true;
				Mythread.writeStatistiks(filename, j + " " + time, overwrite);
				System.out.println("Anzahl Wahrer Werte im Array: " + Mythread.getBoorayTrue());
				System.out.println("------ Zeit bei ["+ j +"]: " + time + "ms ------");
				time=0;
			}			
			Mythread.setWahr(0);
			ret=0;
		}
		
		timeSum=System.currentTimeMillis()-timeSum;
		if(sync)
			System.out.println("Benötigte Zeit mit Synchronisation: " + timeSum);
		else
			System.out.println("Benötigte Zeit ohne Synchronisation: " + timeSum);
		Mythread.showStatistiks(filename);
	}
	public void threadHandler(){
		this.threadHandler(50000, 101, 0, false);
	}
 }
